<template>
  <div class="three-wrapper">
    <div class="box" ref="box"></div>
  </div>
</template>

<script>
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

const clock = new THREE.Clock()
const FPS = 30 // 设置渲染频率为30FBS，也就是每秒调用渲染器render方法大约30次
const renderT = 1 / FPS // 单位秒  间隔多长时间渲染渲染一次
let timeS = 0

export default {
  components: {},
  props: {},
  data() {
    return {
      el: null,
      scene: null,
      camera: null,
      renderer: null,
      controls: null,
      animationFrameId: null,
      spriteTextures: {} // 存储文字精灵纹理
    }
  },
  computed: {},
  watch: {},
  created() {},
  mounted() {
    this.el = this.$refs['box']
    this.clock = new THREE.Clock()

    this.initThree()
  },
  activated() {},
  deactivated() {},
  updated() {},
  beforeDestroy() {
    // 清理资源
    if (this.animationFrameId) {
      cancelAnimationFrame(this.animationFrameId)
    }
    // 释放纹理内存
    Object.values(this.spriteTextures).forEach(texture => {
      if (texture instanceof THREE.Texture) {
        texture.dispose()
      }
    })
  },
  destroyed() {},
  methods: {
    initThree() {
      // 初始化 - 开始
      this.initScene() // 核心： 场景
      this.initCamera() // 核心: 相机
      this.initRender() // 核心 渲染器
      this.initLight()
      this.initControls()
      this.animate()
      this.scene.add(this.setGridHelper(100 * 2, 10 * 2))
      this.scene.add(this.setAxesHelper(100000))
      // 初始化 - 结束

      // 添加物体
      this.addMesh()
      // 添加文字精灵
      this.addTextSprites()
    },

    addMesh() {
      const geometry = new THREE.BoxGeometry(10, 10, 10)
      const material = new THREE.MeshLambertMaterial({
        color: new THREE.Color('#00ff00'),
        transparent: true
      })
      const mesh = new THREE.Mesh(geometry, material)
      this.scene.add(mesh)
    },

    // 添加文字精灵
    addTextSprites() {
      // 创建简单的文字精灵
      this.createSimpleTextSprite()

      // 创建带背景的文字精灵
      // this.createStyledTextSprite()

      // 创建3D对象上的标签精灵
      // this.createObjectLabelSprite()

      // 创建多个随机位置文字精灵
      // this.createRandomTextSprites()
    },

    // 创建简单文字精灵
    createSimpleTextSprite() {
      const text = '简单文字精灵'
      const options = {
        fontColor: '#ffffff',
        backgroundColor: 'rgba(0, 0, 0, 0.8)',
        fontSize: 24,
        padding: 10
      }

      const sprite = this.createTextSprite(text, options)
      sprite.position.set(0, 30, 0)
      this.scene.add(sprite)
    },

    // 创建带样式的文字精灵
    createStyledTextSprite() {
      const text = '样式文字'
      const options = {
        fontColor: '#ffffff',
        backgroundColor: 'rgba(74, 144, 226, 0.9)',
        fontSize: 28,
        padding: 15,
        borderColor: '#ffffff',
        borderWidth: 2,
        borderRadius: 8
      }

      const sprite = this.createTextSprite(text, options)
      sprite.position.set(0, 30, 0)
      this.scene.add(sprite)
    },

    // 创建3D对象上的标签精灵
    createObjectLabelSprite() {
      // 创建一个球体
      const geometry = new THREE.SphereGeometry(8, 32, 32)
      const material = new THREE.MeshLambertMaterial({
        color: new THREE.Color('#ff6b6b'),
        transparent: true
      })
      const sphere = new THREE.Mesh(geometry, material)
      sphere.position.set(20, 15, 30)
      this.scene.add(sphere)

      // 为球体创建文字精灵标签
      const text = '球形物体'
      const options = {
        fontColor: '#333333',
        backgroundColor: 'rgba(255, 255, 255, 0.95)',
        fontSize: 18,
        padding: 8,
        borderColor: '#ff6b6b',
        borderWidth: 2,
        borderRadius: 4
      }

      const sprite = this.createTextSprite(text, options)
      sprite.position.set(20, 25, 30) // 在球体上方
      this.scene.add(sprite)
    },

    // 创建多个随机位置文字精灵
    createRandomTextSprites() {
      const texts = ['标签1', '信息2', '数据3', '提示4', '警告5']
      const colors = ['#4a90e2', '#f5a623', '#7ed321', '#bd10e0', '#d0021b']

      texts.forEach((text, index) => {
        const options = {
          fontColor: '#ffffff',
          backgroundColor: colors[index],
          fontSize: 20,
          padding: 8,
          borderRadius: 4
        }

        const sprite = this.createTextSprite(text, options)
        const x = (Math.random() - 0.5) * 100
        const y = 50 + Math.random() * 30
        const z = (Math.random() - 0.5) * 100
        sprite.position.set(x, y, z)
        this.scene.add(sprite)
      })
    },

    // 创建文字精灵的核心方法
    createTextSprite(text, options = {}) {
      const {
        fontColor = '#ffffff',
        backgroundColor = 'rgba(0, 0, 0, 0.8)',
        fontSize = 24,
        padding = 10,
        borderColor = 'transparent',
        borderWidth = 0,
        borderRadius = 0,
        fontFamily = 'Arial, sans-serif',
        fontWeight = 'normal'
      } = options

      // 创建canvas来绘制文字
      const canvas = document.createElement('canvas')
      const context = canvas.getContext('2d')

      // 设置canvas大小 - 先测量文字宽度
      context.font = `${fontWeight} ${fontSize}px ${fontFamily}`
      const textMetrics = context.measureText(text)
      const textWidth = textMetrics.width
      const textHeight = fontSize

      // 设置canvas尺寸（考虑padding）
      canvas.width = textWidth + padding * 2 + borderWidth * 2
      canvas.height = textHeight + padding * 2 + borderWidth * 2

      // 重新设置字体（因为canvas尺寸改变了）
      context.font = `${fontWeight} ${fontSize}px ${fontFamily}`
      context.textAlign = 'center'
      context.textBaseline = 'middle'

      // 绘制背景
      if (borderWidth > 0) {
        context.fillStyle = borderColor
        this.roundRect(
          context,
          borderWidth / 2,
          borderWidth / 2,
          canvas.width - borderWidth,
          canvas.height - borderWidth,
          borderRadius
        )
        context.fill()
      }

      // 绘制内背景
      context.fillStyle = backgroundColor
      this.roundRect(
        context,
        borderWidth,
        borderWidth,
        canvas.width - borderWidth * 2,
        canvas.height - borderWidth * 2,
        Math.max(0, borderRadius - borderWidth)
      )
      context.fill()

      // 绘制文字
      context.fillStyle = fontColor
      context.fillText(text, canvas.width / 2, canvas.height / 2)

      // 创建纹理
      const texture = new THREE.CanvasTexture(canvas)
      texture.needsUpdate = true

      // 创建精灵材质
      const spriteMaterial = new THREE.SpriteMaterial({
        map: texture,
        transparent: true,
        depthTest: false // 确保文字总是显示在前面
      })

      // 创建精灵
      const sprite = new THREE.Sprite(spriteMaterial)

      // 设置精灵大小（根据canvas尺寸自动调整）
      const scale = 0.1 // 缩放因子，根据需要调整
      sprite.scale.set(canvas.width * scale, canvas.height * scale, 1)

      // 存储纹理以便后续清理
      const textureKey = `text_${text}_${Date.now()}`
      this.spriteTextures[textureKey] = texture

      return sprite
    },

    // 绘制圆角矩形
    roundRect(ctx, x, y, width, height, radius) {
      if (radius > 0) {
        ctx.beginPath()
        ctx.moveTo(x + radius, y)
        ctx.lineTo(x + width - radius, y)
        ctx.quadraticCurveTo(x + width, y, x + width, y + radius)
        ctx.lineTo(x + width, y + height - radius)
        ctx.quadraticCurveTo(
          x + width,
          y + height,
          x + width - radius,
          y + height
        )
        ctx.lineTo(x + radius, y + height)
        ctx.quadraticCurveTo(x, y + height, x, y + height - radius)
        ctx.lineTo(x, y + radius)
        ctx.quadraticCurveTo(x, y, x + radius, y)
        ctx.closePath()
      } else {
        ctx.rect(x, y, width, height)
      }
    },

    setGridHelper(size, divisions) {
      return new THREE.GridHelper(size, divisions)
    },

    setAxesHelper(size) {
      return new THREE.AxesHelper(size)
    },

    // 初始化场景
    initScene() {
      this.scene = new THREE.Scene()
    },

    // 初始化相机
    initCamera() {
      const asp = this.el.offsetWidth / this.el.offsetHeight
      this.camera = new THREE.PerspectiveCamera(45, asp, 0.1, 10000000)
      this.camera.position.set(300, 300, 300)
      this.camera.lookAt(this.scene.position)
      this.scene.add(this.camera)
    },

    initRender(clearColor = '#000') {
      const width = this.el.offsetWidth
      const height = this.el.offsetHeight
      this.renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true
      })
      this.renderer.setPixelRatio(window.devicePixelRatio)
      this.renderer.setSize(width, height)
      this.el.append(this.renderer.domElement)
      // this.renderer.setClearColor(clearColor, 1) // 不设置背景色
    },

    initLight() {
      const ambientLight = new THREE.AmbientLight('#fff', 0.3)
      this.scene.add(ambientLight)
      const directionalLight = new THREE.DirectionalLight('#fff')
      directionalLight.position.set(30, 30, 30).normalize()
      this.scene.add(directionalLight)
    },

    initControls() {
      this.controls = new OrbitControls(
        this.camera,
        this.renderer.domElement,
        {}
      )
    },

    render() {
      const dt = this.clock.getDelta()
      const T = clock.getDelta()
      timeS = timeS + T
      if (timeS > renderT) {
        this.controls.update(dt)
        this.renderer.render(this.scene, this.camera)
      }
    },

    animate() {
      this.render()
      this.animationFrameId = requestAnimationFrame(this.animate)
    }
  },
  filters: {}
}
</script>

<style scoped lang="scss">
.three-wrapper {
  height: 100%;
  position: relative;
  .box {
    height: 100%;
    width: 100%;
    background: url(./images/map-bg.png);
    background-size: cover;
    background-repeat: no-repeat;
    overflow: hidden;
  }
}
</style>
